/** *  В плагине нашел ряд отличий от исходного кода *   измененные строки пометил комментариями (//++   - новые строки ) * *  В будущем желательно устранить эти отличия *//* * Copyright (c) 2009 Anders Ekdahl (http://coffeescripter.com/) * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. * * Version: 1.3.1 * * Demo and documentation: http://coffeescripter.com/code/editable-select/ */(function($) {  var instances = [];  $.fn.editableSelect = function(options) {    var defaults = { bg_iframe: false,                     onSelect: false,                     items_then_scroll: 10,                     case_sensitive: false    };    var settings = $.extend(defaults, options);    // Only do bg_iframe for browsers that need it    if(settings.bg_iframe && !$.browser.msie) {      settings.bg_iframe = false;    };    var instance = false;    $(this).each(function() {      var i = instances.length;      if(typeof $(this).data('editable-selecter') == 'undefined') {        instances[i] = new EditableSelect(this, settings);        $(this).data('editable-selecter', i);      };    });    return $(this);  };  $.fn.editableSelectInstances = function() {    var ret = [];    $(this).each(function() {      if(typeof $(this).data('editable-selecter') != 'undefined') {        ret[ret.length] = instances[$(this).data('editable-selecter')];      };    });    return ret;  };  var EditableSelect = function(select, settings) {    this.init(select, settings);  };  EditableSelect.prototype = {    settings: false,    text: false,    select: false,    wrapper: false,    list_item_height: 20,    list_height: 0,    list_is_visible: false,    hide_on_blur_timeout: false,    bg_iframe: false,    current_value: '',    init: function(select, settings) {      this.settings = settings;      this.select = $(select);      this.text = $('<input type="text">');      this.text.attr('name', this.select.attr('name'));      this.text.data('editable-selecter', this.select.data('editable-selecter'));      // Because we don't want the value of the select when the form      // is submitted      this.select.attr('disabled', 'disabled');      var id = this.select.attr('id');      if(!id) {        id = 'editable-select'+ instances.length;      };      this.text.attr('id', id);      this.text.attr('autocomplete', 'off');      this.text.addClass('editable-select');      this.select.attr('id', id +'_hidden_select');      this.initInputEvents(this.text);      this.duplicateOptions();      this.positionElements();      this.setWidths();      if(this.settings.bg_iframe) {        this.createBackgroundIframe();      };    },    duplicateOptions: function() {      var context = this;      var wrapper = $(document.createElement('div'));      wrapper.addClass('editable-select-options');      var option_list = $(document.createElement('ul'));      wrapper.append(option_list);      var options = this.select.find('option');      options.each(function() {        if($(this).attr('selected')) {          context.text.val($(this).val());          context.current_value = $(this).val();          context.text.attr( 'rel', $(this).attr('id') ); // ++          context.text.addClass( $(this).attr('id') );    // ++        };        var li = $('<li>'+ $(this).val() +'</li>');        li.addClass( $(this).attr('id') ).attr( 'rel', $(this).attr('id') ); // ++        context.initListItemEvents(li);        option_list.append(li);        if($(this).attr('selected')) { // ++        	window.selected_item = li; // ++        }                              // ++      });      this.wrapper = wrapper;      this.checkScroll();    },    checkScroll: function() {      var options = this.wrapper.find('li');      if(options.length > this.settings.items_then_scroll) {        this.list_height = this.list_item_height * this.settings.items_then_scroll;        this.wrapper.css('height', this.list_height +'px');        this.wrapper.css('overflow', 'auto');      } else {        this.wrapper.css('height', 'auto');        this.wrapper.css('overflow', 'visible');      };    },    addOption: function(value) {      var li = $('<li>'+ value +'</li>');      var option = $('<option>'+ value +'</option>');      this.select.append(option);      this.initListItemEvents(li);      this.wrapper.find('ul').append(li);      this.setWidths();      this.checkScroll();    },    initInputEvents: function(text) {      var context = this;      var timer = false;      $(document.body).click(        function() {          context.clearSelectedListItem();          context.hideList();        }      );      text.focus(        function() {          // Can't use the blur event to hide the list, because the blur event          // is fired in some browsers when you scroll the list          context.showList();          context.highlightSelected();        }      ).click(        function(e) {          e.stopPropagation();          context.showList();          context.highlightSelected();        }      ).keydown(        // Capture key events so the user can navigate through the list        function(e) {          switch(e.keyCode) {            // Down            case 40:              if(!context.listIsVisible()) {                context.showList();                context.highlightSelected();              } else {                e.preventDefault();                context.selectNewListItem('down');              };              break;            // Up            case 38:              e.preventDefault();              context.selectNewListItem('up');              break;            // Tab            case 9:              context.hideList(); //context.pickListItem(context.selectedListItem());              break;            // Esc            case 27:              e.preventDefault();              context.hideList();              return false;              break;            // Enter, prevent form submission            case 13:              if (context.list_is_visible){ // ++            	  e.preventDefault();                  context.pickListItem(context.selectedListItem());                  return false;              }                             // ++            default:                        // ++            	if( text.val() != ''){      // ++            		context.hideList();     // ++            	}else{                      // ++            		context.showList();     // ++            	}                           // ++            break;                          // ++          };        }      ).keyup(        function(e) {        	if( text.val() != ''){           // ++        		context.hideList();          // ++        	}else{                           // ++        		context.showList();          // ++        	}                                // ++          // Prevent lots of calls if it's a fast typer          if(timer !== false) {            clearTimeout(timer);            timer = false;          };          timer = setTimeout(            function() {              // If the user types in a value, select it if it's in the list              if(context.text.val() != context.current_value) {                context.current_value = context.text.val();                context.highlightSelected();              };            },            200          );        }      ).keypress(        function(e) {          if (context.list_is_visible){        // ++	          if(e.keyCode == 13) {	            // Enter, prevent form submission	            e.preventDefault();	            return false;	          }else{                            // ++            	if( text.val() != ''){          // ++            		context.hideList();         // ++            	}else{                          // ++            		context.showList();         // ++            	}	          };          };                                    // ++        }      );    },    initListItemEvents: function(list_item) {      var context = this;      list_item.mouseover(        function() {          context.clearSelectedListItem();          context.selectListItem(list_item);        }      ).mousedown(        // Needs to be mousedown and not click, since the inputs blur events        // fires before the list items click event        function(e) {          e.stopPropagation();          context.pickListItem(context.selectedListItem());        }      );    },    selectNewListItem: function(direction) {      var li = this.selectedListItem();      if(!li.length) {        li = this.selectFirstListItem();      };      if(direction == 'down') {        var sib = li.next();      } else {        var sib = li.prev();      };      if(sib.length) {        this.selectListItem(sib);        this.scrollToListItem(sib);        this.unselectListItem(li);      };    },    selectListItem: function(list_item) {      this.clearSelectedListItem();      list_item.addClass('selected');    },    selectFirstListItem: function() {      this.clearSelectedListItem();      var first = this.wrapper.find('li:first');      first.addClass('selected');      return first;    },    unselectListItem: function(list_item) {      list_item.removeClass('selected');    },    selectedListItem: function() {      return this.wrapper.find('li.selected');    },    clearSelectedListItem: function() {      this.wrapper.find('li.selected').removeClass('selected');    },    pickListItem: function(list_item) {      if(list_item.length) {        this.text.val(list_item.text());        this.current_value = this.text.val();      };      if(typeof this.settings.onSelect == 'function') {        this.settings.onSelect.call(this, list_item);      };      this.hideList();    },    listIsVisible: function() {      return this.list_is_visible;    },    showList: function() {      this.wrapper.show();      this.hideOtherLists();      this.list_is_visible = true;      if(this.settings.bg_iframe) {        this.bg_iframe.show();      };    },    highlightSelected: function() {      var context = this;      var current_value = this.text.val();      if(current_value.length < 0) {        if(highlight_first) {          this.selectFirstListItem();        };        return;      };      if(!context.settings.case_sensitive) {        current_value = current_value.toLowerCase();      };      var best_candiate = false;      var value_found = false;      var list_items = this.wrapper.find('li');      list_items.each(        function() {          if(!value_found) {            var text = $(this).text();            if(!context.settings.case_sensitive) {              text = text.toLowerCase();            };            if(text == current_value) {              value_found = true;              context.clearSelectedListItem();              context.selectListItem($(this));              context.scrollToListItem($(this));              return false;            } else if(text.indexOf(current_value) === 0 && !best_candiate) {              // Can't do return false here, since we still need to iterate over              // all list items to see if there is an exact match              best_candiate = $(this);            };          };        }      );      if(best_candiate && !value_found) {        context.clearSelectedListItem();        context.selectListItem(best_candiate);        context.scrollToListItem(best_candiate);      } else if(!best_candiate && !value_found) {        this.selectFirstListItem();      };    },    scrollToListItem: function(list_item) {      if(this.list_height) {        this.wrapper.scrollTop(list_item[0].offsetTop - (this.list_height / 2));      };    },    hideList: function() {      this.wrapper.hide();      this.list_is_visible = false;      if(this.settings.bg_iframe) {        this.bg_iframe.hide();      };    },    hideOtherLists: function() {      for(var i = 0; i < instances.length; i++) {        if(i != this.select.data('editable-selecter')) {          instances[i].hideList();        };      };    },    positionElements: function() {      var offset = this.select.offset();      offset.top += this.select[0].offsetHeight;      this.select.after(this.text);      this.select.hide();      // this.wrapper.css({top: offset.top +'px', left: offset.left +'px'});      $(document.body).append(this.wrapper);      // Need to do this in order to get the list item height      this.wrapper.css('visibility', 'hidden');      this.wrapper.show();      this.list_item_height = this.wrapper.find('li')[0].offsetHeight;      this.wrapper.css('visibility', 'visible');      this.wrapper.hide();    },    setWidths: function() {      // The text input has a right margin because of the background arrow image      // so we need to remove that from the width      var width = this.select.width() + 2;      width = window.selected_item.attr('rel') == 'sltv_openid_logo' ? 171 : 151;  // var padding_right = parseInt(this.text.css('padding-right').replace(/px/, ''), 10);      this.text.width(width);      this.wrapper.width(width+13); // this.wrapper.width(width + 2);      if(this.bg_iframe) {        this.bg_iframe.width(width); //this.bg_iframe.width(width + 4);      };    },    createBackgroundIframe: function() {      var bg_iframe = $('<iframe frameborder="0" class="editable-select-iframe" src="about:blank;"></iframe>');      $(document.body).append(bg_iframe);      bg_iframe.width(this.select.width() + 2);      bg_iframe.height(this.wrapper.height());      bg_iframe.css({top: this.wrapper.css('top'), left: this.wrapper.css('left')});      this.bg_iframe = bg_iframe;    }  };})(jQuery);
